package com.irdstudio.efp.flow.executor.impl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.irdstudio.basic.framework.core.annotation.BeanMapKey;
import com.irdstudio.efp.flow.common.constance.FlowConstance;
import com.irdstudio.efp.flow.common.vo.EngineVO;
import com.irdstudio.efp.flow.executor.PluginTaskExecutor;
import com.irdstudio.efp.flow.service.facade.BizFlowTaskParamService;
import com.irdstudio.efp.flow.service.facade.BizPluginServiceService;
import com.irdstudio.efp.flow.service.facade.InstFlowTaskService;
import com.irdstudio.efp.flow.service.vo.BizFlowTaskParamVO;
import com.irdstudio.efp.flow.service.vo.BizPluginServiceVO;
import com.irdstudio.efp.flow.service.vo.InstFlowTaskVO;
import com.irdstudio.basic.framework.core.util.BeanUtility;
import com.irdstudio.basic.framework.core.util.StringUtil;
import com.irdstudio.basic.framework.core.vo.PluginVO;

/**
 * 
 * 虚基类插件任务执行器，主要提供公用方法
 * 
 * @author Cytus_
 * @since 2018年5月14日 下午2:23:44
 * @version 1.0
 *
 */
public abstract class AbstractPluginTaskExecutor implements PluginTaskExecutor {
	
	private static Logger logger = LoggerFactory.getLogger(AbstractPluginTaskExecutor.class);
	
	@Autowired
	@Qualifier("instFlowTaskService")
	private InstFlowTaskService instFlowTaskService;
	
	@Autowired
	@Qualifier("bizFlowTaskParamService")
	private BizFlowTaskParamService bizFlowTaskParamService;
	
	@Autowired
	@Qualifier("bizPluginServiceService")
	private BizPluginServiceService bizPluginServiceService;
	
	/**
	 * 更新任务状态
	 * @param instNodeId
	 * @param taskId
	 * @param taskStatus
	 * @return
	 */
	protected int updateTaskStateByNodeTaskId(String instNodeId, String taskId, String taskStatus, String errorMsg) {
		InstFlowTaskVO task = new InstFlowTaskVO();
		task.setInstNodeId(instNodeId);
		task.setTaskId(taskId);
		task.setTaskState(taskStatus);
		task.setErrorMsg(errorMsg);
		int record = this.instFlowTaskService.updateTaskStateByNodeTaskId(task);
		logger.info("当前节点实例:"+ instNodeId +", 任务编号:"+ taskId +"更新任务状态为："+ taskStatus +"结束");
		return record;
	}
	
	
	/**
	 * 根据任务ID查询任务对应参数
	 * @param pluginId
	 * @return
	 */
	protected List<BizFlowTaskParamVO> getTaskParamsByTaskId(String taskId) {
		return bizFlowTaskParamService.queryTaskParamsByTaskId(taskId);
	}
	
	
	/**
	 * 根据插件ID查询插件信息
	 * @param pluginId
	 * @return
	 */
	protected BizPluginServiceVO getBizPluginServiceByPluginId(String pluginId) {
		BizPluginServiceVO queryInfo = new BizPluginServiceVO();
		queryInfo.setBizPluginId(pluginId);
		return bizPluginServiceService.queryByPk(queryInfo);
	}
	
	/**
	 * 
	 * @param evo
	 * @param params
	 * @return
	 */
	protected EngineVO dealDefaultParam(EngineVO evo, List<BizFlowTaskParamVO> params) {
		
		if (evo.getPluginVo().getVos().containsKey(FlowConstance.DEFAULT_PLUGIN_VO_KEY) && Objects.nonNull(params) 
		        && StringUtil.isNotEmpty(StringUtil.replaceObjNull(evo.getPluginVo().getVo(FlowConstance.DEFAULT_PLUGIN_VO_KEY)))) {

			Object defaultObject = evo.getPluginVo().getVo(FlowConstance.DEFAULT_PLUGIN_VO_KEY);
			Object pagePluginVO = evo.getPluginVo().getVo(FlowConstance.PAGE_PLUGIN_VO_KEY2);

			if (defaultObject instanceof Map) {
				dealDefaultMapParam(evo, defaultObject, params);
			} else if (defaultObject instanceof List){
				dealDefaultListParam(evo, defaultObject, params);
			} else {
				dealDefaultOtherParam(evo, defaultObject, params);
			}
		
		}
		evo.getPluginVo().remove(FlowConstance.DEFAULT_PLUGIN_VO_KEY);
		return evo;
	}
	
	@SuppressWarnings("unchecked")
	private void dealDefaultListParam(EngineVO evo, Object defaultObject, List<BizFlowTaskParamVO> params) {
		List<Object> listObj = (List<Object>) defaultObject;
		if (Objects.nonNull(listObj) && !listObj.isEmpty()) {
			for (Object dataObj : listObj) {
				if (dataObj instanceof Map) {
					dealDefaultMapParam(evo, dataObj, params);
				} else if (defaultObject instanceof List){
					dealDefaultListParam(evo, dataObj, params);
				} else {
					dealDefaultOtherParam(evo, dataObj, params);
				}
			}
		}
	}


	/**
	 * 
	 * @param evo
	 * @param defaultObject
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private EngineVO dealDefaultOtherParam(EngineVO evo, Object defaultObject, List<BizFlowTaskParamVO> params) {
		for (BizFlowTaskParamVO param : params) {
			String[] genericClass = param.getParamClass().split("@");
			if (genericClass.length == 1 && defaultObject.getClass().getName().equals(genericClass[0])) {
				evo.getPluginVo().addVOs(param.getBizTargetParamCode(), defaultObject);
				evo.getPluginVo().getFlowInVo().add(param.getBizTargetParamCode(), defaultObject);
			} else if (genericClass.length == 2 && defaultObject.getClass().getName().matches(".+List$")) {
				if (genericClass[0].equals(defaultObject.getClass().getName())) {
					List<Object> listObject = (List<Object>) defaultObject;
					if (!listObject.isEmpty() && listObject.get(0).getClass().getName().equals(genericClass[1])) {
						Object paramListObject = listMap2ListBean(listObject, listObject.get(0).getClass().getName());
						evo.getPluginVo().addVOs(param.getBizTargetParamCode(), paramListObject);
						evo.getPluginVo().getFlowInVo().add(param.getBizTargetParamCode(), paramListObject);
					} else {
						logger.warn("未匹配成功, 遗弃对象信息为:"+ defaultObject);
					}
				} else {
					logger.warn("未匹配成功, 遗弃对象信息为:"+ defaultObject);
				}
			} else {
				logger.warn("未匹配成功, 遗弃对象信息为:"+ defaultObject);
			}
		}
		return evo;
	}
	
	
	/**
	 * 处理默认入参为MAP
	 * @param evo
	 * @param defaultObject
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private EngineVO dealDefaultMapParam(EngineVO evo, Object defaultObject, List<BizFlowTaskParamVO> params) {
		for (BizFlowTaskParamVO param : params) {
			String[] genericClass = param.getParamClass().split("@");
			Object currPluginParamObject = null;
			
			Object currInArgObj = defaultObject;
			if (currInArgObj instanceof String || currInArgObj instanceof Number) {
				if (genericClass.length == 1) {
					currPluginParamObject = currInArgObj;
				} else {
					logger.warn("传入参数类型为基础类型, 但配置参数类型类为多个, 忽略处理!");
				}
			} else if (currInArgObj instanceof Map) {
				if (genericClass.length == 1) {
					if (!genericClass[0].matches(".+Map$")) {
						currPluginParamObject = map2Bean((Map<String, Object>)currInArgObj, param.getParamClass());
					} else {
						currPluginParamObject = currInArgObj;
					}
				} else {
					logger.warn("传入参数类型为Map类型, 但配置参数类型类为多个, 忽略处理!");
				}
			} else if (currInArgObj instanceof List && currInArgObj.getClass().getName().equals(genericClass[0])) {
				if (genericClass.length == 1) {
					currPluginParamObject = currInArgObj;
				} else if (genericClass.length == 2){
					currPluginParamObject = listMap2ListBean((List<Object>) currInArgObj, genericClass[1]);
				} else {
					logger.warn("传入参数类型为List类型, 但配置参数类型类为2个以上, 忽略处理!");
				}
			}
			if (Objects.nonNull(currPluginParamObject)) {
				evo.getPluginVo().addVOs(param.getBizTargetParamCode(), currPluginParamObject);
				evo.getPluginVo().getFlowInVo().add(param.getBizTargetParamCode(), currPluginParamObject);
			}
		}
		return evo;
	}

	/**
	 * 
	 * @param dataMap
	 * @param clazz
	 * @return
	 */
	private static Object map2Bean(Map<String, Object> dataMap, String clazz) {
		try {
			if (clazz.matches(".+Map$")) return dataMap;
			return BeanUtility.map2BeanByJSON(dataMap, Class.forName(clazz).newInstance());
		} catch (Exception e) {
		    logger.error("该异常仅为日志输出, 无实际意义!!!!!!", e);
		}
		return null;
	}
	
    
    /**
     * 通过注解将bean转成Map
     * @param bean
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
	public static Map<String, Object> bean2MapByAnno(Object bean) throws Exception {
    	Map<String, Object> map = new HashMap<String, Object>();
    	if (bean instanceof Map) {
    		return (Map<String, Object>)bean;
    	}
    	if (Objects.nonNull(bean)) {
    		Field[] fields = bean.getClass().getDeclaredFields();
    		for (Field field : fields) {
    			BeanMapKey beanMap = field.getAnnotation(BeanMapKey.class);
    			if (Objects.nonNull(beanMap)) {
    				field.setAccessible(true);
    				Object obj = field.get(bean);
    				if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
    					
    				} else if (obj instanceof List) {
    					obj = listBean2MapByAnno((List<Object>) obj);
    				} else {
    					obj = bean2MapByAnno(obj);
    				}
    				map.put(beanMap.value(), obj);
    			}
    		}
    	}
    	
		return map;
    }
    
    /**
     * 配合{@link bean2MapByAnno}使用
     * @param list
     * @return
     * @throws Exception
     */
    public static List<Object> listBean2MapByAnno(List<Object> list) throws Exception {
    	List<Object> listMap = new ArrayList<Object>();
    	if (Objects.nonNull(list) && !list.isEmpty()) {
    		Object o = list.get(0);
    		if (o instanceof String || o instanceof Number || o instanceof Boolean)
    			return list;
    		for (Object obj : list) {
    			listMap.add(bean2MapByAnno(obj));
    		}
    	}
    	return listMap;
    } 
	
	/**
	 * 
	 * @param list
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static Object listMap2ListBean(List<Object> list, String clazz)  {
		List<Object> listObject = new ArrayList<Object>(); 
		try {
			for (int i = 0; i < list.size(); i++) {
				Object object = list.get(i);
				Object exachgeObj = object;
				if (object instanceof Map) {
					exachgeObj = BeanUtility.map2Bean((Map<String, Object>) object, Class.forName(clazz).newInstance());
				} else if (object instanceof List) {
					List<Object> childList = (List<Object>) object;
					if (!childList.isEmpty()) {
						exachgeObj = listMap2ListBean(childList, childList.get(i).getClass().getName());
					} else {
						exachgeObj = childList;
					}
				}
				listObject.add(exachgeObj);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return listObject;
	}
	
	/**
	 * 从pluginvo 中取值
	 * @param vo
	 * @param key
	 * @return
	 */
	protected Object getPluginValue(PluginVO vo, String key) {
		logger.info("当前需要从PluginVO对象中获得去的对象key为:"+ key);
		Object value = null;
		String[] keys = key.split("\\.");
		if (StringUtil.isNotEmpty(key)) {
    		if (keys.length == 1) {
    		    value = vo.getVo(key);
    		} else {
    			try {
    				Object obj = vo.getVos();
    				for (int i = 0; i < keys.length; i++) {
    					obj = BeanUtility.getProptery(obj, keys[i]);
    				}
    				value = obj;
    			} catch (Exception e) {
    				logger.error(e.getMessage(), e);
    			}
    		}
		}
		logger.debug("从PluginVO中获取的对象为key["+ key +"], value["+ value +"]");
		return value;
	}
	
}
